package trees.tree

import trees.settings.Settings

class ImmutableTree(override val name:String, val rooted:Boolean, override val weight:Double, val accessNode:ImmutableNode, val treeList:List[Int], val idList:List[Int])extends AbstractTree(name, rooted, weight, accessNode,treeList,idList) {

    var treeHashCode = 0

    def getLeafs():List[Int] = {
        accessNode.getLeafs()
        //accessNode.children.foldLeft(List[Int]()){ (childs:List[Int], n) => childs ::: n.getLeafs() }
    }

    def changeMutability():MutableTree = {
        accessNode.changeMutability match {
            case m:MutableNode =>
                new MutableTree(name,rooted,weight,m,treeList,idList)
            case _ =>
                throw new Error("Error converting the accessNode to a mutable node")
        }

    }

    def reRoot(ids:List[Int]):ImmutableTree ={
        //reroot has to be done twice to ensure that the minimum common node is found
        if(ids.size==ids.intersect(idList).size){
            //reroot
            val tmp=changeMutability
            tmp.reRoot(ids)
            tmp.changeMutability
        }else{
            throw new Error("There exists ids in the list that are not included in the tree: "+ids.filter((e1)=>idList.exists(e1!=_)).foldLeft("")(_+"\n"+_))
        }
    }

    def reRoot(id:Int):ImmutableTree = {
        reRoot(List[Int](id))
    }

//    def reRoot(label:String):ImmutableTree = {
//        reRoot(List[String](label))
//    }

//    def reRoot(labels:List[String]):ImmutableTree = {
//        if(labels.map(IdFactory.contains(_)).foldLeft(true)(_&&_)){
//            reRoot(labels.map(IdFactory.getID(_)))
//        }else{
//            throw new Error("No tree contains the the labels: "+labels.filter(IdFactory.contains(_)).foldLeft("")(_+"\n"+_))
//        }
//    }

  override def hashCode():Int = {
      if (treeHashCode == 0){
          treeHashCode = treeList.hashCode
      }
      treeHashCode
  }

  override def equals(t:Any):Boolean = t match{
      case t:ImmutableTree =>
        treeList == t.treeList
            //    name == t.name && weight == t.weight && rooted == t.rooted && treeList == t.treeList
      case t:MutableTree =>
          treeList == t.treeList
        //name == t.name && weight == t.weight && rooted == t.rooted && treeList == t.treeList
      case t:AbstractTree =>
        name == t.name && weight == t.weight
      case _ => false
  }


}
